import { findDom, compareTwoVDom } from "./react-dom";

export let updaterQueue = {
    isBatchingUpdate: false,
    updaters: new Set(), // 一个setState后可能会触发多个组件更新 set去除重复
    batchUpdate: () => { // 循环执行所有的updater的更新方法
        for (let updater of updaterQueue.updaters) {
            updater.updateComponent()
        }
        updaterQueue.updaters.clear() // 清空updaters
        updaterQueue.isBatchingUpdate = false
    }
}

class Updater {
    constructor(classInstance) {
        this.classInstance = classInstance
        this.pendingState = []
        this.callbacks = []
    }
    addState(preState, callback = () => { }) {
        this.pendingState.push(preState)
        this.callbacks.push(callback)
        this.emitUpdate()
    }
    emitUpdate(nextProps) {
        this.nextProps = nextProps
        if (updaterQueue.isBatchingUpdate) { // 批量更新时 记录所有要更新的updater
            updaterQueue.updaters.add(this)
        } else { // 非批量时 直接执行更新方法
            this.updateComponent()
        }

    }
    updateComponent() {
        let { classInstance, pendingState, nextProps } = this
        if (nextProps || pendingState.length > 0) { // 包含待修改的State
            this.shouldUpdate(classInstance, nextProps, this.getState());
        }
    }
    getState() {
        let { classInstance, } = this
        let state = classInstance.state
        this.pendingState.forEach((newState,) => {
            if (typeof newState === 'function') { // setState第一个参数为函数时 去执行结果 并传入oldState
                newState = newState(state)
            }
            state = {
                ...state,
                ...newState
            }
        })
        this.pendingState = []
        return state
    }
    shouldUpdate(classInstance, nextProps, newState) {
        classInstance.state = newState
        this.callbacks.forEach((cb) => {// 新的state被赋值后 统一调用cbs
            cb(newState)
        })
        this.callbacks = []

        let isUpdate = true; // 是否需要更新
        if (classInstance.shouldComponentUpdate) {
            isUpdate = classInstance.shouldComponentUpdate(nextProps, newState)
        }

        if (isUpdate) {
            if (classInstance.componentWillUpdate) { // 更新前
                classInstance.componentWillUpdate()
            }
            if (nextProps) {
                classInstance.props = nextProps // 修改props
            }
            classInstance.forceUpdate()

        }


    }
}


class Component {
    static isReactClassComponents = true
    constructor(props) {
        this.props = props
        this.updater = new Updater(this)
    }
    setState(preState, callback) {
        this.updater.addState(preState, callback)
    }
    forceUpdate() {
        let oldRenderVDom = this.oldRenderVDom // 老的虚拟dom
        let dom = findDom(oldRenderVDom) // 真实dom 
        if (this.constructor.contextType) {
            this.context = this.constructor.contextType._currentValue
        }
        let newRenderVDom = this.render()  // 新的虚拟dom
        let snapShop = this.getSnapshotBeforeUpdate && this.getSnapshotBeforeUpdate()
        compareTwoVDom(dom.parentNode, oldRenderVDom, newRenderVDom)
        this.oldRenderVDom = newRenderVDom // 页面更新后 将新虚拟dom赋值给老虚拟dom
        if (this.constructor.getDerivedStateFromProps) {
            let newState = this.constructor.getDerivedStateFromProps(this.props, this.state)
            this.state = {
                ...this.state, ...newState
            }
        }

        if (this.componentDidUpdate) { // 更新后
            this.componentDidUpdate(this.props, this.state, snapShop)
        }
    }
}

export default Component